package org.glandais.profiler;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.Date;

import javax.swing.JFrame;

import org.glandais.profiler.beans.MethodTrace;
import org.glandais.profiler.beans.TraceStack;
import org.glandais.profiler.ui.AnalyzerFrame;
import org.jfree.ui.RefineryUtilities;

import com.thoughtworks.xstream.XStream;

public class TraceAnalyzer {

	private static final String EMPTY = ""; //$NON-NLS-1$
	private static final String CLOSE = "ms)"; //$NON-NLS-1$
	private static final String OPEN = "("; //$NON-NLS-1$
	private static final String OUT = "<< "; //$NON-NLS-1$
	private static final String IN = ">> "; //$NON-NLS-1$
	private static final String SEPARATOR = "************************************************"; //$NON-NLS-1$
	private static final String SPACE = " "; //$NON-NLS-1$
	static final String[] tabs = new String[1000];

	static {
		StringBuilder sb = new StringBuilder(EMPTY);
		for (int i = 0; i < 1000; i++) {
			tabs[i] = sb.toString();
			sb.append(SPACE);
		}
	}

	private static final void log(TraceStack traceStack, String tolog) {
		System.out.println(traceStack.threadId + SPACE + tolog);
	}

	/**
	 * @param args
	 */
	@SuppressWarnings("unchecked")
	public static void main(String[] args) throws Throwable {
		if (args.length > 0) {
			// if (args[0].equals("profile")) {
			// attachAgent();
			// } else {
			for (String arg : args) {
				XStream xstream = Agent.createXStream();
				BufferedInputStream bis = new BufferedInputStream(new FileInputStream(arg));
				ObjectInputStream xOIS = xstream.createObjectInputStream(bis);
				Object readObject = xOIS.readObject();
				ArrayList<TraceStack> stacks = null;
				if (readObject instanceof ArrayList) {
					stacks = (ArrayList<TraceStack>) readObject;
				} else {
					stacks = new ArrayList<TraceStack>(1);
					stacks.add((TraceStack) readObject);
				}
				for (TraceStack traceStack : stacks) {
					logTrace(traceStack);
				}
			}
			// }
		} else {
			AnalyzerFrame analyzerFrame = new AnalyzerFrame(Messages.getString("TraceAnalyzer.JAVA_PROFILER")); //$NON-NLS-1$
			analyzerFrame.pack();
			RefineryUtilities.centerFrameOnScreen(analyzerFrame);
			analyzerFrame.setVisible(true);
			analyzerFrame.setExtendedState(JFrame.MAXIMIZED_BOTH);
		}
	}

	/*
	private static void attachAgent() throws Throwable {
		URL resourceURL = TraceAnalyzer.class.getClassLoader().getResource(
				"org/glandais/profiler/TraceAnalyzer.class");
		JarURLConnection tmpConnection = (JarURLConnection) resourceURL
				.openConnection();
		String profilerPath = tmpConnection.getJarFile().getName();

		List<VirtualMachineDescriptor> vms = VirtualMachine.list();
		int i = 0;
		for (VirtualMachineDescriptor virtualMachineDescriptor : vms) {
			System.out.println(i++ + " " + virtualMachineDescriptor.id() + " "
					+ virtualMachineDescriptor.displayName());
		}
		int vm = 0;
		int ch;
		do {
			StringBuffer sb = new StringBuffer();
			while ((ch = System.in.read()) != 13) {
				sb.append((char) ch);
			}
			String choice = sb.toString();
			try {
				vm = Integer.parseInt(choice);
			} catch (NumberFormatException e) {
				vm = -1;
			}
		} while (vm < 0 || vm >= vms.size());
		VirtualMachine virtualMachine = VirtualMachine.attach(vms.get(vm).id());
		virtualMachine.loadAgent(profilerPath, "");
		virtualMachine.detach();
	}
	*/

	public static final void logTrace(TraceStack traceStack) {
		log(traceStack, SEPARATOR);
		log(traceStack, Messages.getString("TraceAnalyzer.THREAD_NAME") + traceStack.threadName); //$NON-NLS-1$
		log(traceStack, Messages.getString("TraceAnalyzer.STACK_START") + new Date(traceStack.stackStart).toString()); //$NON-NLS-1$
		logMethod(0, traceStack, traceStack.entryMethod);
		log(traceStack, SEPARATOR);
	}

	private static final void logMethod(int i, TraceStack traceStack, MethodTrace traceMethod) {
		log(traceStack, tabs[i] + IN + traceMethod.called + SPACE + traceMethod.signature);
		for (MethodTrace subTraceMethod : traceMethod.subMethods) {
			logMethod(i + 1, traceStack, subTraceMethod);
		}
		log(traceStack, tabs[i] + OUT + OPEN + traceMethod.getDurationMillis() + CLOSE + SPACE + traceMethod.called
				+ SPACE + traceMethod.signature);
	}
}
